package com.blackcat.oauth2.config;

import com.blackcat.oauth2.exception.AuthExceptionEntryPoint;
import com.blackcat.oauth2.exception.CustomWebResponseExceptionTranslator;
import com.blackcat.oauth2.service.UserAuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * Oauth配置文件
 * @author blackcat
 * @date 2023/12/25 15:55
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Resource
    AuthenticationManager authenticationManager;
//
//    @Resource
//    RedisConnectionFactory redisConnectionFactory;

    @Autowired(required = false)
    private CustomWebResponseExceptionTranslator customWebResponseExceptionTranslator;

    @Autowired(required = false)
    UserAuthService userAuthService;

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Resource
    DataSource dataSource;

    @Override
    public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception {
        // 内存存储配置信息+密码模式
        serviceConfig(0, clientDetailsServiceConfigurer, dataSource, "password");
    }

    /**
     * 服务配置，如授权方式，token过期时间等.
     *
     * @param flag                           内存和数据库标识，0：内存；1：数据库
     * @param clientDetailsServiceConfigurer 配置器
     * @param dataSource                     数据源
     * @param grantType                      授权类型，password：密码模式；authorization_code：授权码模式
     * @throws Exception 异常
     */
    private void serviceConfig(int flag, ClientDetailsServiceConfigurer clientDetailsServiceConfigurer, DataSource dataSource, String grantType) throws Exception {
//        if (flag == 1) {
//            clientDetailsServiceConfigurer.jdbc(dataSource);
//        } else {
        clientDetailsServiceConfigurer
                //存储到内存中
                .inMemory()
                //配置client_id
                .withClient("client")
                //配置client-secret
                .secret(new BCryptPasswordEncoder().encode("123456"))
                //配置访问token的有效期
                .accessTokenValiditySeconds(3600)
                //配置刷新token的有效期
                .refreshTokenValiditySeconds(864000)
                //配置redirect_uri，用于授权成功后跳转
//                .redirectUris("http://www.baidu.com")
                //配置申请的权限范围
                .scopes("all")
                //配置grant_type，表示授权类型
                .authorizedGrantTypes("password","refresh_token");
//        }
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpointsConfig) throws Exception {
        // 默认情况下，授权码存储在内存中：InMemoryAuthorizationCodeServices，
        // 所以，不用配置
        endpointsConfig.tokenStore(new InMemoryTokenStore()) //增加 TokenStore 配置
                .authenticationManager(authenticationManager) //使用密码模式需要配置
                .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST) //支持GET,POST请求
                .userDetailsService(userAuthService); //设置userDetailsService刷新token时候会用到
        endpointsConfig.exceptionTranslator(customWebResponseExceptionTranslator);//错误异常
    }

//    /**
//     * 配置授权码存储位置.
//     *
//     * @param flag                                 授权码存储位置标识：0，内存；1：数据库
//     * @param endpointsConfig                      端配置
//     * @param randomValueAuthorizationCodeServices 授权码存储位置
//     */
//    private void codeStoreEndpointConfig(int flag, AuthorizationServerEndpointsConfigurer endpointsConfig, RandomValueAuthorizationCodeServices randomValueAuthorizationCodeServices) {
//        if (flag == 1) {
//            // 授权码存储数据库，需要配置jdbc存储
//            endpointsConfig.authorizationCodeServices(randomValueAuthorizationCodeServices);
//        }
//    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer serverSecurityConfig) throws Exception {
        //允许表单认证
        serverSecurityConfig.allowFormAuthenticationForClients();
        //添加tokan校验失败返回消息
        serverSecurityConfig.authenticationEntryPoint(new AuthExceptionEntryPoint());
    }

}
